/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ts, native, HomeCheckHint } from 'qvog-dsl';

const SEVERITY = 2;
const DOC_PATH = 'docs/no-control-regex.md';
const DESCRIPTION = 'Suggestion: Disallow control characters in regular expressions.';

export default native<HomeCheckHint>()()
  .match((node): node is ts.NewExpression | ts.CallExpression | ts.BinaryExpression => {
    return ts.isNewExpression(node) || ts.isCallExpression(node) || ts.isBinaryExpression(node);
  })
  .when((node): boolean => {
    if (ts.isNewExpression(node) || ts.isCallExpression(node)) {
      const expr = node.expression;
      if (!ts.isIdentifier(expr) || expr.text !== 'RegExp') { return false };

      const args = node.arguments;
      if (!args || args.length === 0) { return false };

      if (ts.isStringLiteral(args[0]) && hasControlCharacters(args[0].text)) {
        return true;
      }
    } else if (ts.isBinaryExpression(node)) {
      if (!isAssignmentOperator(node.operatorToken.kind)) { return false };

      if (ts.isStringLiteral(node.right) && hasControlCharacters(node.right.text)) {
        return true;
      }
    }
    return false;
  })
  .report({
    severity: SEVERITY,
    description: DESCRIPTION,
    docPath: DOC_PATH,
  });

function isAssignmentOperator(kind: ts.SyntaxKind): boolean {
  return kind === ts.SyntaxKind.EqualsToken;
}

function hasControlCharacters(pattern: string): boolean {
  // \t & 0x00~0x1F
  const regex = /\\x[0-1][0-9A-Fa-f]|\\u00[0-1][0-9A-Fa-f]|\\u\{[A-Fa-f]{1,2}\}|\t/g;
  return regex.test(pattern);
}
